﻿/*
Copyright (c) 2009 Vratislav Cermak (vratacermak@gmail.com)
 
This file is part of TeachMe Project. See http://code.google.com/p/teach-me for more information.
 
TeachMe is an open source project. Using of TeachMe is free of charge.
It is distributed under GNU General Public License version 3 (GPLv3).
GPLv3 can be found at http://www.gnu.org/licenses/gpl.html.
 
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

using System;
using System.Threading;
using System.Windows.Forms;
using log4net.Config;
using TeachMe.Application.Properties;

namespace TeachMe.Application
{

    static class Program
    {
        [STAThread]
        static void Main()
        {
            bool createdNew;

            using (Mutex mutex = new Mutex(true, "996cf813-a25b-4b07-b30b-d7a1d3fe696f", out createdNew))
            {
                if (createdNew)
                {
                    XmlConfigurator.Configure();
                    // BasicConfigurator.Configure();

                    System.Windows.Forms.Application.EnableVisualStyles();
                    System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);

                    System.Windows.Forms.Application.ThreadException += OnApplicationThreadException;
                    AppDomain.CurrentDomain.UnhandledException += OnCurrentDomainUnhandledException;

                    using (Root root = new Root())
                    {
                        // have to force saving of generated application id
                        using (root.UserSettings.Edit())
                        {
                            Logging.Info(typeof(Program), "Instance id: {0}", root.UserSettings.Id.Value);
                        }

                        if (root.JustInstalled)
                        {
                            if (MessageBox.Show(Resources.CheckForUpdatesQuestion, Resources.MessageBoxCaption, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
                            {
                                using (root.UserSettings.Edit())
                                {
                                    root.UserSettings.NewVersionCheckInterval.Value = Interval.Never;
                                }
                            }
                        }

                        using (NotifyIcon notifyIcon = InitializeNotifyIcon(root))
                        {
                            if (root.JustInstalled)
                            {
                                root.ShowBaloon(Resources.MessageBoxCaption, Resources.JustInstalledText);
                                root.AddDefaultDictionaries();
                            }

                            System.Windows.Forms.Application.AddMessageFilter(new MessageFilter(root));

                            // it be here or no working :)
                            root.SyncContext = SynchronizationContext.Current;

                            System.Windows.Forms.Application.Run();
                        }
                    }

                    Logging.Debug(typeof(Program), "Exiting.");
                }
                else
                {
                    MessageBox.Show(Resources.AlreadyRunning, Resources.MessageBoxCaption, MessageBoxButtons.OK, MessageBoxIcon.Information);
                }

                // this is used to ensure that mutex is not collected while program is running
                GC.KeepAlive(mutex);
            }
        }

        static void OnCurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Logging.Error(typeof(Program), (Exception)e.ExceptionObject, "Domain exception has been thrown.");
        }

        static void OnApplicationThreadException(object sender, ThreadExceptionEventArgs e)
        {
            Logging.Error(typeof(Program), e.Exception, "Thread exception has been thrown.");

            try
            {
                MessageBox.Show(Resources.ThreadExceptionThrown, Resources.MessageBoxCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch
            {
                Logging.Error(typeof(Program), "Fatal error - error dialog could not be shown.");

                System.Windows.Forms.Application.Exit();
            }
        }

        public class MessageFilter : IMessageFilter
        {
            private readonly Root _root;

            public MessageFilter(Root root)
            {
                _root = root;
            }

            public bool PreFilterMessage(ref Message m)
            {
                if (m.Msg == (int)Win32.Messages.WM_HOTKEY)
                {
                    _root.HandleHotkey((ushort)m.WParam);

                    return true;
                }

                return false;
            }
        }

        private static NotifyIcon InitializeNotifyIcon(Root root)
        {
            NotifyIcon notifyIcon = new NotifyIcon
                                      {
                                          Visible = true,
                                          Icon = Resources.AppIcon
                                      };

            notifyIcon.MouseClick += delegate(object obj, MouseEventArgs e)
                                       {
                                           // single left display entries if not topmost

                                           if (e.Button == MouseButtons.Left)
                                           {
                                               root.DisplayManager.ShowEntries();
                                           }
                                       };

            notifyIcon.MouseDoubleClick += delegate(object obj, MouseEventArgs e)
                                             {
                                                 // double left will create new entry or just display all opened windows

                                                 if (e.Button == MouseButtons.Left)
                                                 {
                                                     if (root.FormsManager.Count == 0)
                                                     {
                                                         root.CreateEntry();
                                                     }
                                                     else
                                                     {
                                                         root.FormsManager.ActivateForms();
                                                     }
                                                 }
                                             };

            notifyIcon.MouseMove += delegate
                                        {
                                            notifyIcon.Text = root.GetNotifyIconText();

                                            if (notifyIcon.ContextMenuStrip == null)
                                            {
                                                notifyIcon.ContextMenuStrip = root.ContextMenusManager.Get(ContextMenuType.Tray);
                                            }
                                        };

            root.UserSettings.Language.Changed += delegate { notifyIcon.ContextMenuStrip = null; };
            root.BallonRequested += ((ender, eventArgs) => notifyIcon.ShowBalloonTip(5 * 1000, eventArgs.Title, eventArgs.Text, ToolTipIcon.Info));

            return notifyIcon;
        }
    }
}
